package cn.coder.toolkit;

import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * @author com.mrathena on 2018-09-27 14:59:04
 */
public final class DateTimeKit {

	public static void main(String[] args) {
		java.util.Date date = Date.New.withDate(2025, 6, 9);
		System.out.println(DateTimeKit.Format.Date.toCompactDateTime(date));
		System.out.println(DateTimeKit.Format.Date.toDateTime(DateTimeKit.Date.Plus.days(date, 1)));
	}

	private DateTimeKit() {}

	// 时段重叠判断

	public static boolean isLocalDateTimeDurationOverlap(LocalDateTime start, LocalDateTime stop, LocalDateTime anotherStart, LocalDateTime anotherStop) {
		if (start == null || stop == null || anotherStart == null || anotherStop == null) {
			throw new RuntimeException("四个LocalDateTime必须都不为null");
		}
		if (start.isAfter(stop) || anotherStart.isAfter(anotherStop)) {
			throw new RuntimeException("两组结束时间必须晚于同组开始时间");
		}
		LocalDateTime minDateTime = start.isBefore(anotherStart) ? start : anotherStart;
		LocalDateTime maxDateTime = stop.isBefore(anotherStop) ? anotherStop : stop;
		long nanos = getEpochNano(maxDateTime) - getEpochNano(minDateTime);
		long nanos1 = getEpochNano(stop) - getEpochNano(start);
		long nanos2 = getEpochNano(anotherStop) - getEpochNano(anotherStart);
		return nanos <= (nanos1 + nanos2);
	}

	public static long getEpochNano(LocalDateTime localDateTime) {
		Instant instant = localDateTime.atZone(ZoneId.systemDefault()).toInstant();
		return instant.getEpochSecond() * 1_000_000_000 + instant.getNano();
	}

	public static boolean isLocalDateDurationOverlap(LocalDate start, LocalDate stop, LocalDate anotherStart, LocalDate anotherStop) {
		return isLocalDateTimeDurationOverlap(start.atStartOfDay(), stop.atStartOfDay(), anotherStart.atStartOfDay(), anotherStop.atStartOfDay());
	}

	public static boolean isDataDurationOverlap(java.util.Date start, java.util.Date stop, java.util.Date anotherStart, java.util.Date anotherStop) {
		if (start == null || stop == null || anotherStart == null || anotherStop == null) {
			throw new RuntimeException("四个LocalDateTime必须都不为null");
		}
		if (start.after(stop) || anotherStart.after(anotherStop)) {
			throw new RuntimeException("两组结束时间必须晚于同组开始时间");
		}
		java.util.Date minDate = start.before(anotherStart) ? start : anotherStart;
		java.util.Date maxDate = stop.before(anotherStop) ? anotherStop : stop;
		long millis = maxDate.getTime() - minDate.getTime();
		long millis1 = stop.getTime() - start.getTime();
		long millis2 = anotherStop.getTime() - anotherStart.getTime();
		return millis <= (millis1 + millis2);
	}

	// Pattern
	public static class Pattern {
		public static final String PATTERN_YEAR = "yyyy";
		public static final String PATTERN_MONTH = "MM";
		public static final String PATTERN_DAY = "dd";
		public static final String PATTERN_HOUR = "HH";
		public static final String PATTERN_MINUTE = "mm";
		public static final String PATTERN_SECOND = "ss";
		public static final String PATTERN_MILLI = "SSS";
		//
		public static final String PATTERN_DATE = "yyyy-MM-dd";
		public static final String PATTERN_TIME = "HH:mm:ss";
		public static final String PATTERN_TIME_MILLI = "HH:mm:ss.SSS";
		public static final String PATTERN_DATE_TIME = "yyyy-MM-dd HH:mm:ss";
		public static final String PATTERN_DATE_TIME_MILLI = "yyyy-MM-dd HH:mm:ss.SSS";
		//
		public static final String PATTERN_COMPACT_YEAR_MONTH = "yyyyMM";
		public static final String PATTERN_COMPACT_DATE = "yyyyMMdd";
		public static final String PATTERN_COMPACT_TIME = "HHmmss";
		public static final String PATTERN_COMPACT_TIME_MILLI = "HHmmssSSS";
		public static final String PATTERN_COMPACT_DATE_TIME = "yyyyMMddHHmmss";
		public static final String PATTERN_COMPACT_DATE_TIME_MILLI = "yyyyMMddHHmmssSSS";
	}

	// Formatter
	public static class Formatter {
		public static final DateTimeFormatter FORMATTER_YEAR = DateTimeFormatter.ofPattern(Pattern.PATTERN_YEAR);
		public static final DateTimeFormatter FORMATTER_MONTH = DateTimeFormatter.ofPattern(Pattern.PATTERN_MONTH);
		public static final DateTimeFormatter FORMATTER_DAY = DateTimeFormatter.ofPattern(Pattern.PATTERN_DAY);
		public static final DateTimeFormatter FORMATTER_HOUR = DateTimeFormatter.ofPattern(Pattern.PATTERN_HOUR);
		public static final DateTimeFormatter FORMATTER_MINUTE = DateTimeFormatter.ofPattern(Pattern.PATTERN_MINUTE);
		public static final DateTimeFormatter FORMATTER_SECOND = DateTimeFormatter.ofPattern(Pattern.PATTERN_SECOND);
		public static final DateTimeFormatter FORMATTER_MILLI = DateTimeFormatter.ofPattern(Pattern.PATTERN_MILLI);
		//
		public static final DateTimeFormatter FORMATTER_DATE = DateTimeFormatter.ofPattern(Pattern.PATTERN_DATE);
		public static final DateTimeFormatter FORMATTER_TIME = DateTimeFormatter.ofPattern(Pattern.PATTERN_TIME);
		public static final DateTimeFormatter FORMATTER_TIME_MILLI = DateTimeFormatter.ofPattern(Pattern.PATTERN_TIME_MILLI);
		public static final DateTimeFormatter FORMATTER_DATE_TIME = DateTimeFormatter.ofPattern(Pattern.PATTERN_DATE_TIME);
		public static final DateTimeFormatter FORMATTER_DATE_TIME_MILLI = DateTimeFormatter.ofPattern(Pattern.PATTERN_DATE_TIME_MILLI);
		//
		public static final DateTimeFormatter FORMATTER_COMPACT_YEAR_MONTH = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_YEAR_MONTH);
		public static final DateTimeFormatter FORMATTER_COMPACT_DATE = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_DATE);
		public static final DateTimeFormatter FORMATTER_COMPACT_TIME = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_TIME);
		public static final DateTimeFormatter FORMATTER_COMPACT_TIME_MILLI = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_TIME_MILLI);
		public static final DateTimeFormatter FORMATTER_COMPACT_DATE_TIME = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_DATE_TIME);
		public static final DateTimeFormatter FORMATTER_COMPACT_DATE_TIME_MILLI = DateTimeFormatter.ofPattern(Pattern.PATTERN_COMPACT_DATE_TIME_MILLI);
	}

	// 转换
	public static class Per {
		public static final int HOURS_PER_DAY = 24;
		public static final int MINUTES_PER_HOUR = 60;
		public static final int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
		public static final int SECONDS_PER_MINUTE = 60;
		public static final int SECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR;
		public static final int SECONDS_PER_DAY = SECONDS_PER_HOUR * HOURS_PER_DAY;
		public static final long MILLIS_PER_SECOND = 1000L;
		public static final long MILLIS_PER_DAY = MILLIS_PER_SECOND * SECONDS_PER_DAY;
		public static final long MICROS_PER_SECOND = 1000_000L;
		public static final long MICROS_PER_DAY = MICROS_PER_SECOND * SECONDS_PER_DAY;
		public static final long NANOS_PER_MILLI = 1000_000L;
		public static final long NANOS_PER_SECOND =  1000_000_000L;
		public static final long NANOS_PER_MINUTE = NANOS_PER_SECOND * SECONDS_PER_MINUTE;
		public static final long NANOS_PER_HOUR = NANOS_PER_MINUTE * MINUTES_PER_HOUR;
		public static final long NANOS_PER_DAY = NANOS_PER_HOUR * HOURS_PER_DAY;
	}

	// Date 和 LocalDateTime,LocalDate,LocalTime 的互相转换
	public static class Convert {
		public static class Date {
			public static java.time.LocalDateTime toLocalDateTime(java.util.Date date) {
				return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
			}
			public static java.time.LocalDate toLocalDate(java.util.Date date) {
				return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
			}
			public static java.time.LocalTime toLocalTime(java.util.Date date) {
				return date.toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
			}
		}
		public static class LocalDateTime {
			public static java.util.Date toDate(java.time.LocalDateTime localDateTime) {
				return java.util.Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
			}
			public static java.time.LocalDate toLocalDate(java.time.LocalDateTime localDateTime) {
				return localDateTime.toLocalDate();
			}
			public static java.time.LocalTime toLocalTime(java.time.LocalDateTime localDateTime) {
				return localDateTime.toLocalTime();
			}
		}
		public static class LocalDate {
			public static java.util.Date toDate(java.time.LocalDate localDate) {
				return java.util.Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
			}
			public static java.time.LocalDateTime toLocalDateTime(java.time.LocalDate localDate) {
				return localDate.atStartOfDay();
			}
		}
		public static class LocalTime {
			public static java.util.Date toDate(java.time.LocalTime localTime) {
				return java.util.Date.from(java.time.LocalDate.now().atTime(localTime).atZone(ZoneId.systemDefault()).toInstant());
			}
			public static java.time.LocalDateTime toLocalDateTime(java.time.LocalTime localTime) {
				return java.time.LocalDate.now().atTime(localTime);
			}
		}
	}

	// Date 加减创建操作
	public static class Date {
		public static class New {
			public static java.util.Date withDateTime(int year, int month, int day, int hour, int minute, int second) {
				return Convert.LocalDateTime.toDate(LocalDateTime.of(year, month, day, hour, minute, second));
			}
			public static java.util.Date withDateTimeMilli(int year, int month, int day, int hour, int minute, int second, int milli) {
				return Convert.LocalDateTime.toDate(LocalDateTime.of(year, month, day, hour, minute, second, milli * (int) Per.NANOS_PER_MILLI));
			}
			public static java.util.Date withDate(int year, int month, int day) {
				return Convert.LocalDate.toDate(LocalDate.of(year, month, day));
			}
			public static java.util.Date withTime(int hour, int minute, int second) {
				return Convert.LocalTime.toDate(LocalTime.of(hour, minute, second));
			}
			public static java.util.Date withTimeMilli(int hour, int minute, int second, int milli) {
				return Convert.LocalTime.toDate(LocalTime.of(hour, minute, second, milli * (int) Per.NANOS_PER_MILLI));
			}
		}
		public static class Plus {
			public static java.util.Date years(java.util.Date date, long year) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusYears(year));
			}
			public static java.util.Date months(java.util.Date date, long month) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusMonths(month));
			}
			public static java.util.Date weeks(java.util.Date date, long week) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusWeeks(week));
			}
			public static java.util.Date days(java.util.Date date, long day) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusDays(day));
			}
			public static java.util.Date hours(java.util.Date date, long hour) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusHours(hour));
			}
			public static java.util.Date minutes(java.util.Date date, long minute) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusMinutes(minute));
			}
			public static java.util.Date seconds(java.util.Date date, long second) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusSeconds(second));
			}
			public static java.util.Date millis(java.util.Date date, long milli) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).plusNanos(milli * Per.NANOS_PER_MILLI));
			}
		}
		public static class Minus {
			public static java.util.Date years(java.util.Date date, long year) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusYears(year));
			}
			public static java.util.Date months(java.util.Date date, long month) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusMonths(month));
			}
			public static java.util.Date weeks(java.util.Date date, long week) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusWeeks(week));
			}
			public static java.util.Date days(java.util.Date date, long day) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusDays(day));
			}
			public static java.util.Date hours(java.util.Date date, long hour) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusHours(hour));
			}
			public static java.util.Date minutes(java.util.Date date, long minute) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusMinutes(minute));
			}
			public static java.util.Date seconds(java.util.Date date, long second) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusSeconds(second));
			}
			public static java.util.Date millis(java.util.Date date, long milli) {
				return Convert.LocalDateTime.toDate(Convert.Date.toLocalDateTime(date).minusNanos(milli * Per.NANOS_PER_MILLI));
			}
		}
	}

	// 格式化
	public static class Format {
		public static class Now {
			public static String to(DateTimeFormatter formatter) {
				return java.time.LocalDateTime.now().format(formatter);
			}
			public static String toDate() {
				return java.time.LocalDate.now().format(Formatter.FORMATTER_DATE);
			}
			public static String toTime() {
				return java.time.LocalTime.now().format(Formatter.FORMATTER_TIME);
			}
			public static String toTimeMilli() {
				return java.time.LocalTime.now().format(Formatter.FORMATTER_TIME_MILLI);
			}
			public static String toDateTime() {
				return java.time.LocalDateTime.now().format(Formatter.FORMATTER_DATE_TIME);
			}
			public static String toDateTimeMilli() {
				return java.time.LocalDateTime.now().format(Formatter.FORMATTER_DATE_TIME_MILLI);
			}
			public static String toCompactDate() {
				return java.time.LocalDate.now().format(Formatter.FORMATTER_COMPACT_DATE);
			}
			public static String toCompactTime() {
				return java.time.LocalTime.now().format(Formatter.FORMATTER_COMPACT_TIME);
			}
			public static String toCompactTimeMilli() {
				return java.time.LocalTime.now().format(Formatter.FORMATTER_COMPACT_TIME_MILLI);
			}
			public static String toCompactDateTime() {
				return java.time.LocalDateTime.now().format(Formatter.FORMATTER_COMPACT_DATE_TIME);
			}
			public static String toCompactDateTimeMilli() {
				return java.time.LocalDateTime.now().format(Formatter.FORMATTER_COMPACT_DATE_TIME_MILLI);
			}
		}
		public static class Date {
			public static String to(java.util.Date date, DateTimeFormatter formatter) {
				return Convert.Date.toLocalDateTime(date).format(formatter);
			}
			public static String toDate(java.util.Date date) {
				return to(date, Formatter.FORMATTER_DATE);
			}
			public static String toTime(java.util.Date date) {
				return to(date, Formatter.FORMATTER_TIME);
			}
			public static String toTimeMilli(java.util.Date date) {
				return to(date, Formatter.FORMATTER_TIME_MILLI);
			}
			public static String toDateTime(java.util.Date date) {
				return to(date, Formatter.FORMATTER_DATE_TIME);
			}
			public static String toDateTimeMilli(java.util.Date date) {
				return to(date, Formatter.FORMATTER_DATE_TIME_MILLI);
			}
			public static String toCompactDate(java.util.Date date) {
				return to(date, Formatter.FORMATTER_COMPACT_DATE);
			}
			public static String toCompactTime(java.util.Date date) {
				return to(date, Formatter.FORMATTER_COMPACT_TIME);
			}
			public static String toCompactTimeMilli(java.util.Date date) {
				return to(date, Formatter.FORMATTER_COMPACT_TIME_MILLI);
			}
			public static String toCompactDateTime(java.util.Date date) {
				return to(date, Formatter.FORMATTER_COMPACT_DATE_TIME);
			}
			public static String toCompactDateTimeMilli(java.util.Date date) {
				return to(date, Formatter.FORMATTER_COMPACT_DATE_TIME_MILLI);
			}
		}
		public static class LocalDateTime {
			public static String to(java.time.LocalDateTime localDateTime, DateTimeFormatter formatter) {
				return localDateTime.format(formatter);
			}
			public static String toDate(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_DATE);
			}
			public static String toTime(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_TIME);
			}
			public static String toTimeMilli(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_TIME_MILLI);
			}
			public static String toDateTime(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_DATE_TIME);
			}
			public static String toDateTimeMilli(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_DATE_TIME_MILLI);
			}
			public static String toCompactDate(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_COMPACT_DATE);
			}
			public static String toCompactTime(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_COMPACT_TIME);
			}
			public static String toCompactTimeMilli(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_COMPACT_TIME_MILLI);
			}
			public static String toCompactDateTime(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_COMPACT_DATE_TIME);
			}
			public static String toCompactDateTimeMilli(java.time.LocalDateTime localDateTime) {
				return to(localDateTime, Formatter.FORMATTER_COMPACT_DATE_TIME_MILLI);
			}
		}
		public static class LocalDate {
			public static String to(java.time.LocalDate localDate, DateTimeFormatter formatter) {
				return localDate.format(formatter);
			}
			public static String toDate(java.time.LocalDate localDate) {
				return to(localDate, Formatter.FORMATTER_DATE);
			}
			public static String toCompactDate(java.time.LocalDate localDate) {
				return to(localDate, Formatter.FORMATTER_COMPACT_DATE);
			}
		}
		public static class LocalTime {
			public static String to(java.time.LocalTime localTime, DateTimeFormatter formatter) {
				return localTime.format(formatter);
			}
			public static String toTime(java.time.LocalTime localTime) {
				return to(localTime, Formatter.FORMATTER_TIME);
			}
			public static String toTimeMilli(java.time.LocalTime localTime) {
				return to(localTime, Formatter.FORMATTER_TIME_MILLI);
			}
			public static String toCompactTime(java.time.LocalTime localTime) {
				return to(localTime, Formatter.FORMATTER_COMPACT_TIME);
			}
			public static String toCompactTimeMilli(java.time.LocalTime localTime) {
				return to(localTime, Formatter.FORMATTER_COMPACT_TIME_MILLI);
			}
		}
	}

	// 转换
	public static class Parse {
		public static class Date {
			public static java.util.Date from(String string, DateTimeFormatter formatter) {
				return Convert.LocalDateTime.toDate(java.time.LocalDateTime.parse(string, formatter));
			}
			public static java.util.Date fromDateTime(String string) {
				return Convert.LocalDateTime.toDate(java.time.LocalDateTime.parse(string, Formatter.FORMATTER_DATE_TIME));
			}
			public static java.util.Date fromDateTimeMilli(String string) {
				return Convert.LocalDateTime.toDate(java.time.LocalDateTime.parse(string, Formatter.FORMATTER_DATE_TIME_MILLI));
			}
			public static java.util.Date fromCompactDateTime(String string) {
				return Convert.LocalDateTime.toDate(java.time.LocalDateTime.parse(string, Formatter.FORMATTER_COMPACT_DATE_TIME));
			}
			public static java.util.Date fromCompactDateTimeMilli(String string) {
				return Convert.LocalDateTime.toDate(java.time.LocalDateTime.parse(string, Formatter.FORMATTER_COMPACT_DATE_TIME_MILLI));
			}
		}
		public static class LocalDateTime {
			public static java.time.LocalDateTime from(String string, DateTimeFormatter formatter) {
				return java.time.LocalDateTime.parse(string, formatter);
			}
			public static java.time.LocalDateTime fromDateTime(String string) {
				return java.time.LocalDateTime.parse(string, Formatter.FORMATTER_DATE_TIME);
			}
			public static java.time.LocalDateTime fromDateTimeMilli(String string) {
				return java.time.LocalDateTime.parse(string, Formatter.FORMATTER_DATE_TIME_MILLI);
			}
			public static java.time.LocalDateTime fromCompactDateTime(String string) {
				return java.time.LocalDateTime.parse(string, Formatter.FORMATTER_COMPACT_DATE_TIME);
			}
			public static java.time.LocalDateTime fromCompactDateTimeMilli(String string) {
				return java.time.LocalDateTime.parse(string, Formatter.FORMATTER_COMPACT_DATE_TIME_MILLI);
			}
		}
		public static class LocalDate {
			public static java.time.LocalDate from(String string, DateTimeFormatter formatter) {
				return java.time.LocalDate.parse(string, formatter);
			}
			public static java.time.LocalDate fromDate(String string) {
				return java.time.LocalDate.parse(string, Formatter.FORMATTER_DATE);
			}
			public static java.time.LocalDate fromCompactDate(String string) {
				return java.time.LocalDate.parse(string, Formatter.FORMATTER_COMPACT_DATE);
			}
		}
		public static class LocalTime {
			public static java.time.LocalTime from(String string, DateTimeFormatter formatter) {
				return java.time.LocalTime.parse(string, formatter);
			}
			public static java.time.LocalTime fromTime(String string) {
				return java.time.LocalTime.parse(string, Formatter.FORMATTER_TIME);
			}
			public static java.time.LocalTime fromTimeMilli(String string) {
				return java.time.LocalTime.parse(string, Formatter.FORMATTER_TIME_MILLI);
			}
			public static java.time.LocalTime fromCompactTime(String string) {
				return java.time.LocalTime.parse(string, Formatter.FORMATTER_COMPACT_TIME);
			}
			public static java.time.LocalTime fromCompactTimeMilli(String string) {
				return java.time.LocalTime.parse(string, Formatter.FORMATTER_COMPACT_TIME_MILLI);
			}
		}
	}

}